package com.yinsin.utils;

import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import com.yinsin.other.LogHelper;
import com.yinsin.security.Base64;

/**
 * 图片处理工具类，提供一些常用的方法包括：
 * <ul>
 * <li>根据BufferedImage获取图片RGB数组</li>
 * <li>裁剪图片，并保存</li>
 * <li>根据图片路径裁剪图片</li>
 * <li>裁剪图片</li>
 * <li>旋转图片为指定角度</li>
 * <li>屏幕截图</li>
 * <li>从本地文件读取目标图片</li>
 * <li>图片加亮</li>
 * <li>获取图片的RPG灰度像素点</li>
 * <li>获取图片的ARPG像素点</li>
 * <li>将图片写入磁盘</li>
 * <li>图片加水印（图片/文字）</li>
 * <li>获取文件base64编码</li>
 * </ul>
 * 
 * @author Yisin
 */
public class ImageUtils {
    protected static final LogHelper log = LogHelper.getLogger(ImageUtils.class);

    /**
     * 根据BufferedImage获取图片RGB数组
     * 
     * @param bfImage
     * @return
     */
    public static int[][] getImageRGB(BufferedImage bfImage) {
        int width = bfImage.getWidth();
        int height = bfImage.getHeight();
        int[][] result = new int[height][width];
        for (int h = 0; h < height; h++) {
            for (int w = 0; w < width; w++) {
                // 使用getRGB(w,
                // h)获取该点的颜色值是ARGB，而在实际应用中使用的是RGB，所以需要将ARGB转化成RGB，即bufImg.getRGB(w,
                // h) & 0xFFFFFF。
                result[h][w] = bfImage.getRGB(w, h) & 0xFFFFFF;
            }
        }
        return result;
    }

    /**
     * 裁剪图片，并保存
     * 
     * @param src 原图
     * @param dest 目标图
     * @param x x坐标
     * @param y y坐标
     * @param w 宽度
     * @param h 高度
     * @throws IOException IO异常
     */
    public static void cutImage(String src, String dest, int x, int y, int w, int h) throws IOException {
        BufferedImage image = cutImage(getBfImageFromPath(src), x, y, w, h);
        writeImage(image, dest);
    }

    /**
     * 根据图片路径裁剪图片
     * @param src 图片路径
     * @param x x坐标
     * @param y y坐标
     * @param w 宽度
     * @param h 高度
     * @return BufferedImage
     * @throws IOException IO异常
     */
    public static BufferedImage cutImage(String src, int x, int y, int w, int h) throws IOException {
        return cutImage(getBfImageFromPath(src), x, y, w, h);
    }

    /**
     * 裁剪图片
     * 
     * @param image BufferedImage
     * @param x x坐标
     * @param y y 坐标
     * @param w 宽度
     * @param h 高度
     * @return BufferedImage
     */
    public static BufferedImage cutImage(BufferedImage image, int x, int y, int w, int h) {
        if (x >= 0 && (x + w <= image.getWidth()) && y >= 0 && y + h <= image.getHeight()) {
            return image.getSubimage(x, y, w, h);
        }
        return image;
    }

    /**
     * 旋转图片为指定角度
     * 
     * @param bufferedimage
     *            目标图像
     * @param degree
     *            旋转幅度
     * @return
     */
    public static BufferedImage rotateImage(final BufferedImage bufferedimage, final double degree) {
        int w = bufferedimage.getWidth();
        int h = bufferedimage.getHeight();
        int type = bufferedimage.getColorModel().getTransparency();
        BufferedImage img;
        Graphics2D graphics2d;
        (graphics2d = (img = new BufferedImage(w, h, type)).createGraphics()).setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2d.rotate(degree, w / 2, h / 2);
        graphics2d.drawImage(bufferedimage, 0, 0, null);
        graphics2d.dispose();
        return img;
    }

    /**
     * 屏幕截图
     * 
     * @param savePath
     *            保存路径
     * 
     * @return 返回BufferedImage
     * @throws AWTException
     */
    public BufferedImage getFullScreenShot(String savePath) throws AWTException {
        BufferedImage bfImage = null;
        int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        Robot robot = new Robot();
        bfImage = robot.createScreenCapture(new Rectangle(0, 0, width, height));
        if (savePath != null) {
            writeImage(bfImage, savePath);
        }
        return bfImage;
    }

    /**
     * 从本地文件读取目标图片
     * 
     * @param imagePath
     *            - 图片绝对路径
     * @return 本地图片的BufferedImage对象
     * @throws IOException
     */
    public static BufferedImage getBfImageFromPath(String imagePath) throws IOException {
        BufferedImage bfImage = ImageIO.read(new File(imagePath));
        return bfImage;
    }

    /**
     * 图片加亮
     * 
     * @param img
     *            BufferedImage
     * @param lightenValue
     *            加亮值 -255 - 255
     * @return BufferedImage
     */
    public static BufferedImage imageLighten(BufferedImage img, int lightenValue) {
        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                // 获取到rgb的组合值
                int rgb = img.getRGB(x, y);
                Color color = new Color(rgb);
                int r = color.getRed() + lightenValue;
                int g = color.getGreen() + lightenValue;
                int b = color.getBlue() + lightenValue;
                if (r > 255) {
                    r = 255;
                } else if (r < 0) {
                    r = 0;
                }

                if (g > 255) {
                    g = 255;
                } else if (g < 0) {
                    g = 0;
                }

                if (b > 255) {
                    b = 255;
                } else if (b < 0) {
                    b = 0;
                }

                color = new Color(r, g, b);
                img.setRGB(x, y, color.getRGB());
            }
        }
        return img;
    }

    /**
     * 获取图片的RPG灰度像素点
     * 
     * @param image
     * @return
     */
    public static int[][] getImageRGBGray(BufferedImage image) {
        int width = image.getWidth(), height = image.getHeight();
        int[][] resRgb = new int[width][height];
        int r, g, b;
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                int pixel = image.getRGB(i, j); // 下面三行代码将一个数字转换为RGB数字
                // resRgb[i][j] = pixel & 0xFFFFFF;
                r = (pixel & 0xff0000) >> 16;
                g = (pixel & 0xff00) >> 8;
                b = (pixel & 0xff);
                int gray = (int) (r * 0.3 + g * 0.59 + b * 0.11); // 计算灰度值
                resRgb[i][j] = gray;
            }
        }
        return resRgb;
    }

    /**
     * 获取图片的ARPG像素点
     * 
     * @param image
     * @return
     */
    public static List<Integer> getImageARGB(BufferedImage image) {
        int width = image.getWidth(), height = image.getHeight();
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                list.add(image.getRGB(i, j));
            }
        }
        return list;
    }

    /**
     * 将图片写入磁盘
     * 
     * @param image
     * @param path
     */
    public static void writeImage(BufferedImage image, String path) {
        try {
            ImageIO.write(image, "jpg", new File(path));
        } catch (IOException e) {
            log.error("写入图片失败：" + e.getMessage());
        }
    }

    /**
     * 添加图片水印
     * 
     * @param imgPath 图片路径
     * @param markPath 水印图片路径
     * @param x 水印左上角x坐标
     * @param y 水印左上角y坐标
     * @param alpha 水印透明度
     * @throws IOException
     */
    public static void waterMark(String imgPath, String markPath, int x, int y, float alpha) throws IOException {
        // 加载待处理图片文件
        File imgFile = new File(imgPath);
        Image img = ImageIO.read(imgFile);
        String parent = imgFile.getParentFile().getPath() + "\\";
        String name = imgFile.getName();
        int index = name.lastIndexOf(".");
        String bakName = name.substring(0, index) + "_new" + name.substring(index);

        BufferedImage image = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.drawImage(img, 0, 0, null);

        // 加载水印图片文件
        Image src_biao = ImageIO.read(new File(markPath));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        g.drawImage(src_biao, x, y, null);
        g.dispose();

        // 保存处理后的文件
        writeImage(image, parent + bakName);
    }

    /**
     * 添加文字水印
     * 
     * @param imgPath 图片路径
     * @param newPath 被加水印后的图片路径
     * @param text 水印文字
     * @param font 水印文字字体
     * @param color 水印文字颜色
     * @param x 水印文字左上角x坐标
     * @param y 水印文字左上角y坐标
     * @param alpha 水印文字透明度
     * @throws IOException
     */
    public static void textMark(String imgPath, String newPath, String text, Font font, Color color, int x, int y, float alpha) throws IOException {
        Font Dfont = (font == null) ? new Font("宋体", 0, 13) : font;
        File imgFile = new File(imgPath);
        Image img = ImageIO.read(imgFile);

        BufferedImage image = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();

        g.drawImage(img, 0, 0, null);
        g.setColor(color == null ? Color.BLACK : color);
        g.setFont(Dfont);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        g.drawString(text, x, y);
        g.dispose();

        writeImage(image, newPath);
    }
    
    /**
     * 图片添加文字水印
     * @param imgPath 图片路径
     * @param text 水印文字
     * @param x 水印文字左上角x坐标
     * @param y 水印文字左上角y坐标
     * @throws IOException
     */
    public static void textMark(String imgPath, String text, int x, int y) throws IOException {
    	textMark(imgPath, imgPath, text, null, null, x, y, 1.0f);
    }
    
    /**
     * 图片添加文字水印
     * @param img 图片对象
     * @param text 水印文字
     * @param x 水印文字左上角x坐标
     * @param y 水印文字左上角y坐标
     * @return img 图片对象
     * @throws IOException
     */
    public static Image textMark(Image img, String text, int x, int y) throws IOException {
    	BufferedImage image = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        
        g.drawImage(img, 0, 0, null);
        g.setColor(Color.BLACK);
        g.setFont(new Font("宋体", 0, 13));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0f));
        g.drawString(text, x, y);
        g.dispose();

        return image;
    }
    
    /**
     * 图片添加文字水印
     * @param imgPath 图片路径
     * @param newPath 添加水印后的图片路径
     * @param text 水印文字
     * @param font 水印文字字体
     * @param color 水印文字颜色
     * @param alpha 水印文字透明度，0.0~1.0
     * @param position 水印文字位置：0左上角,1右上角,2右下角,3左下角,4上居中,5中居中,6下居中
     * @throws IOException
     */
    public static void textMark(String imgPath, String newPath, String text, Font font, Color color, float alpha, int position) throws IOException {
    	Image img = ImageIO.read(new File(imgPath));
    	int width = img.getWidth(null);
    	int height = img.getHeight(null);
    	if(null == font) font = new Font("宋体", 0, 20);
    	if(null == color) color = Color.BLACK;
    	String a = new String(text.getBytes("gb2312"), "iso-8859-1");
    	int x = (int)((font.getSize()/2 + 1) * a.length());
    	int y = (int)(font.getSize()/2);
    	if(position == 0){// 左上角
    		x = 5;
    		y = y * 2;
    	} else if(position == 1){// 右上角
    		x = width - x;
    		y = y * 2;
    	} else if(position == 2){ // 右下角
    		x = width - x;
    		y = height - y;
    	} else if(position == 3){ // 左下角
    		x = 5;
    		y = height - y;
    	} else if(position == 4){ // 上居中
    		x = (width - x) / 2;
    		y = y * 2;
    	} else if(position == 5){ // 中居中
    		x = (width - x) / 2;
    		y = (height - y)/2;
    	} else if(position == 6){ // 下居中
    		x = (width - x) / 2;
    		y = height - y;
    	}
    	textMark(imgPath, newPath, text, font, color, x, y, alpha);
    }
    
    /**
     * 图片添加文字水印
     * @param imgPath 图片路径
     * @param text 水印文字
     * @param position 水印文字位置：0左上角,1右上角,2右下角,3左下角,4上居中,5中居中,6下居中
     * @throws IOException
     */
    public static void textMark(String imgPath, String text, int position) throws IOException {
    	textMark(imgPath, imgPath, text, null, null, 1.0f, position);
    }

    /**
     * 获取文件base64编码
     * @param path
     * @return
     */
    public static String getImageBase64(String path) {
        return getImageBase64(new File(path));
    }

    /**
     * 获取文件base64编码
     * @param file
     * @return
     */
    public static String getImageBase64(File file) {
        byte[] data = null;
        // 读取图片字节数组
        try {
            InputStream in = new FileInputStream(file);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.getEncoder().encodeToString(data);// 返回Base64编码过的字节数组字符串
    }

    public static void main(String[] args) {
        try {
            System.out.println(getImageBase64("d:/sss/qrcode.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
